package de.fhaugsburg.games.boardgames.scrabble;

import java.util.ArrayList;
import java.util.List;

import de.fhaugsburg.games.boardgames.Board;
import de.fhaugsburg.games.boardgames.CircularList;
import de.fhaugsburg.games.boardgames.GridPoint;
import de.fhaugsburg.games.boardgames.Player;
import de.fhaugsburg.games.boardgames.PlayerMode;
import de.fhaugsburg.games.boardgames.RandomPool;
import de.fhaugsburg.games.boardgames.exceptions.GameException;
import de.fhaugsburg.games.boardgames.scrabble.exceptions.NoEmptySquareException;

/**
 * The scrabbleengine manage putting of a letter, the calculation of the points, the player order, etc.
 * 
 * @author r4smus
 * 
 */
public class ScrabbleEngine {

	private ScrabbleBoard board;
	private ScrabblePlayer currentPlayer;
	private int currentPoints = 0;
	private int wordMultiplier = 1;
	private PlayerMode playerMode = PlayerMode.MULTI;
	private RandomPool<LetterPiece> pool = new RandomPool<LetterPiece>();
	private CircularList<ScrabblePlayer> playerList = new CircularList<ScrabblePlayer>();
	private State currentState = State.INITIAL;

	public ScrabbleEngine() {
		board = new ScrabbleBoard();
		initialPool();

	}

	/**
	 * put a piece on an specific empty square and add the points to the attribute currentPoints.
	 * 
	 * @param piece
	 * @param row
	 * @param column
	 * @throws GameException
	 */
	public void setPiece(LetterPiece piece, GridPoint point) throws GameException {
		currentPlayer.giveAway(piece);
		if (!(board.isEmpty(point)))
			throw new NoEmptySquareException(point);
		board.putPiece(piece, point);
		currentPoints += calcPoints(piece, point);

	}

	/**
	 * 
	 * multiply the points for a letter with its letterMultiplier and if it is on a wordmultiplier square set the wordmultiplier attribute.
	 * 
	 * @param piece
	 * @param row
	 * @param column
	 * @return letterPoints * letterMultiplier
	 */
	private int calcPoints(LetterPiece piece, GridPoint point) {
		int letterPoints = piece.getPoints();
		int letterMultiplier = 1;
		letterMultiplier = board.getDetails(point).getLetterMultiplier();
		if (wordMultiplier < board.getDetails(point).getWordMultiplier())
			wordMultiplier = board.getDetails(point).getWordMultiplier();
		return letterPoints * letterMultiplier;
	}

	public ScrabblePlayer getCurrentPlayer() {
		return currentPlayer;
	}

	public void setCurrentPlayer(ScrabblePlayer currentPlayer) {
		this.currentPlayer = currentPlayer;
	}

	public ScrabbleBoard getBoard() {
		return board;
	}

	/**
	 * sets the playerMode in order of a String.
	 * 
	 * @param mode
	 */
	public void setPlayerMode(String mode) {
		if (mode.equals("MP"))
			this.playerMode = PlayerMode.MULTI;
		if (mode.equals("SP"))
			this.playerMode = PlayerMode.SINGLE;
	}

	public PlayerMode getPlayerMode() {
		return playerMode;
	}

	/**
	 * reset the engine.
	 */
	public void reset() {
		wordMultiplier = 1;
		currentPoints = 0;

	}

	/**
	 * fills the pool with all available letters.
	 */
	private void initialPool() {
		LetterPiece[] letterPieceVal = LetterPiece.values();
		for (int i = 0; i < letterPieceVal.length; i++) {
			for (int j = 0; j < letterPieceVal[i].getCount(); j++) {
				pool.put(letterPieceVal[i]);
			}
		}
	}

	/**
	 * Add all players to the playerList attribute and give each player 7 letters from the pool.
	 * 
	 * @param allPlayers
	 */
	public void initialPlayerList(String[] input) {
		ScrabblePlayer[] allPlayers = new ScrabblePlayer[input.length];
		for (int i = 0; i < allPlayers.length; i++) {
			allPlayers[i] = new ScrabblePlayer(input[i]);
			playerList.add(allPlayers[i]);
		}
		for (ScrabblePlayer scrabblePlayer : playerList.getAll()) {
			List<LetterPiece> list = new ArrayList<LetterPiece>(7);
			for (int i = 0; i < 7.; i++) {
				list.add(pool.take());
			}
			scrabblePlayer.receiveAll(list);
		}
		currentPlayer = playerList.getAll().get(0);

	}

	public State getCurrentState() {
		return currentState;
	}

	public void setCurrentState(State currentState) {
		this.currentState = currentState;
		switch (currentState) {
		case INITIAL:

			break;
		case DROPPING:

			break;
		case COMMITED:
			int totalPoints = currentPoints * wordMultiplier;
			currentPlayer.addPoints(totalPoints);
			reFillLetterSet();
			reset();

			break;
		case NEXT:
			currentPlayer = playerList.next();

		default:
			break;
		}
	}
/**
 * 
 * @return the available pieces from the current player
 */
	public List<LetterPiece> getLetterSet() {
		return currentPlayer.getAllPieces();
	}

	private void reFillLetterSet() {
		if (currentPlayer.getAllPieces().size() < 7) {
			int numberOfPieces = currentPlayer.getAllPieces().size();
			for (int i = 0; i < 7 - numberOfPieces; i++) {
				currentPlayer.receive(pool.take());
			}

		}
	}

	public enum State {
		INITIAL, DROPPING, COMMITED, NEXT;
	}

}
